package pl.th.permission;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Dialog;
import android.content.Context;

import androidx.annotation.Nullable;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import pl.th.permission.dialog.CustomDialog;

@SuppressLint("InlinedApi")
public class DefaultProxyFragment extends ProxyFragment {

    private static final Map<String, String> GROUP_MAP = new HashMap<>();

    static {
        GROUP_MAP.put(PermissionCompat.PERMISSION_CREATE_NOTIFICATION, PermissionCompat.PERMISSION_GROUP_NOTIFICATION);
        GROUP_MAP.put(Manifest.permission.REQUEST_INSTALL_PACKAGES, Manifest.permission.REQUEST_INSTALL_PACKAGES);
        GROUP_MAP.put(Manifest.permission.SYSTEM_ALERT_WINDOW, Manifest.permission.SYSTEM_ALERT_WINDOW);
        GROUP_MAP.put(Manifest.permission.PACKAGE_USAGE_STATS, Manifest.permission.PACKAGE_USAGE_STATS);
        GROUP_MAP.put(Manifest.permission.WRITE_SETTINGS, Manifest.permission.WRITE_SETTINGS);
        GROUP_MAP.put(Manifest.permission.MANAGE_EXTERNAL_STORAGE, Manifest.permission_group.STORAGE);
        GROUP_MAP.put(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission_group.STORAGE);
        GROUP_MAP.put(Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission_group.STORAGE);
        GROUP_MAP.put(Manifest.permission.READ_CALENDAR, Manifest.permission_group.CALENDAR);
        GROUP_MAP.put(Manifest.permission.WRITE_CALENDAR, Manifest.permission_group.CALENDAR);
        GROUP_MAP.put(Manifest.permission.CAMERA, Manifest.permission_group.CAMERA);
        GROUP_MAP.put(Manifest.permission.READ_CALL_LOG, Manifest.permission_group.CALL_LOG);
        GROUP_MAP.put(Manifest.permission.WRITE_CALL_LOG, Manifest.permission_group.CALL_LOG);
        GROUP_MAP.put(Manifest.permission.PROCESS_OUTGOING_CALLS, Manifest.permission_group.CALL_LOG);
        GROUP_MAP.put(Manifest.permission.READ_PHONE_STATE, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.ADD_VOICEMAIL, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.USE_SIP, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.CALL_PHONE, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.ACCEPT_HANDOVER, Manifest.permission_group.PHONE);
        GROUP_MAP.put(Manifest.permission.READ_CONTACTS, Manifest.permission_group.CONTACTS);
        GROUP_MAP.put(Manifest.permission.WRITE_CONTACTS, Manifest.permission_group.CONTACTS);
        GROUP_MAP.put(Manifest.permission.GET_ACCOUNTS, Manifest.permission_group.CONTACTS);
        GROUP_MAP.put(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission_group.LOCATION);
        GROUP_MAP.put(Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission_group.LOCATION);
        GROUP_MAP.put(Manifest.permission.ACCESS_BACKGROUND_LOCATION, Manifest.permission_group.LOCATION);
        GROUP_MAP.put(Manifest.permission.RECORD_AUDIO, Manifest.permission_group.MICROPHONE);
        GROUP_MAP.put(Manifest.permission.BODY_SENSORS, Manifest.permission_group.SENSORS);
        GROUP_MAP.put(Manifest.permission.SEND_SMS, Manifest.permission_group.SMS);
        GROUP_MAP.put(Manifest.permission.RECEIVE_SMS, Manifest.permission_group.SMS);
        GROUP_MAP.put(Manifest.permission.READ_SMS, Manifest.permission_group.SMS);
        GROUP_MAP.put(Manifest.permission.RECEIVE_WAP_PUSH, Manifest.permission_group.SMS);
        GROUP_MAP.put(Manifest.permission.RECEIVE_MMS, Manifest.permission_group.SMS);
        GROUP_MAP.put(Manifest.permission.ACTIVITY_RECOGNITION, Manifest.permission_group.ACTIVITY_RECOGNITION);
        GROUP_MAP.put(Manifest.permission.BLUETOOTH_SCAN, Manifest.permission_group.NEARBY_DEVICES);
        GROUP_MAP.put(Manifest.permission.BLUETOOTH_ADVERTISE, Manifest.permission_group.NEARBY_DEVICES);
        GROUP_MAP.put(Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission_group.NEARBY_DEVICES);
    }


    private int showRationaleCount = 0;

    @Nullable
    @Override
    protected Dialog createReminderDialog(List<String> permissions) {
        if (!existSpecialPermissionInList(permissions)) {
            return null;
        } else {
            Set<String> reminderSet = new LinkedHashSet<>();
            for (String permission : permissions) {
                reminderSet.add(convertToExplanation(permission));
            }
            CustomDialog customDialog = new CustomDialog(getContext());
            customDialog.setTitle(R.string.th_permission_compat_reminder_title);
            customDialog.setHeaderMessage(R.string.th_permission_compat_header_message);
            customDialog.setPermissions(new ArrayList<>(reminderSet));
            customDialog.setPositiveListener((dialog, which) -> {
                dialog.dismiss();
                if (!DefaultProxyFragment.this.isAdded()) return;
                requestPermission(permissions);
            });
            customDialog.setNegativeListener((dialog, which) -> {
                dialog.dismiss();
                if (!DefaultProxyFragment.this.isAdded()) return;
                onAllProcessorTraversed();
            });
            return customDialog;
        }
    }

    @SuppressWarnings("ConstantConditions")
    private boolean existSpecialPermissionInList(List<String> permissions) {
        for (String permission : permissions) {
            if (PermissionCompat.isSpecialPermission(permission)) {
                if (Manifest.permission.MANAGE_EXTERNAL_STORAGE.equals(permission)) {
                    return Utils.isAndroidRAndUp(osVersion) && Utils.isAndroidRAndUp(targetVersion)
                            && !PermissionCompat.isManageExtStorageGranted(getContext());
                }
                return !PermissionCompat.isPermissionGranted(getActivity(), permission);
            }
        }
        return false;
    }

    protected Dialog createRationaleDialog(final List<String> grantedList, final List<String> deniedList) {
        showRationaleCount++;
        if (showRationaleCount > 1) {
            return null;
        } else {
            Set<String> reminderSet = new LinkedHashSet<>();
            for (String permission : deniedList) {
                reminderSet.add(convertToExplanation(permission));
            }
            CustomDialog customDialog = new CustomDialog(getContext());
            customDialog.setTitle(R.string.th_permission_compat_rational_title);
            customDialog.setFooterMessage(R.string.th_permission_compat_footer_message);
            customDialog.setPermissions(new ArrayList<>(reminderSet));
            customDialog.setPositiveListener((dialog, which) -> {
                dialog.dismiss();
                if (!DefaultProxyFragment.this.isAdded()) return;
                requestPermissionAgain(deniedList);
            });
            customDialog.setNegativeListener((dialog, which) -> {
                dialog.dismiss();
                if (!DefaultProxyFragment.this.isAdded()) return;
                endRequestPermission(grantedList, deniedList);
            });
            return customDialog;
        }
    }

    @SuppressWarnings({"ConstantConditions"})
    private String convertToExplanation(String permission) {
        final Context context = getContext();
        final String group = GROUP_MAP.getOrDefault(permission, "");
        String explanation;
        switch (group) {
            case PermissionCompat.PERMISSION_GROUP_NOTIFICATION:
                explanation = context.getString(R.string.th_permission_compat_show_notification);
                break;
            case Manifest.permission.WRITE_SETTINGS:
                explanation = context.getString(R.string.th_permission_compat_write_setting);
                break;
            case Manifest.permission.REQUEST_INSTALL_PACKAGES:
                explanation = context.getString(R.string.th_permission_compat_install_packages);
                break;
            case Manifest.permission.SYSTEM_ALERT_WINDOW:
                explanation = context.getString(R.string.th_permission_compat_system_alert_window);
                break;
            case Manifest.permission.PACKAGE_USAGE_STATS:
                explanation = context.getString(R.string.th_permission_compat_package_usage_stats);
                break;
            case Manifest.permission_group.STORAGE:
                explanation = context.getString(R.string.th_permission_compat_storage);
                break;
            case Manifest.permission_group.CALENDAR:
                explanation = context.getString(R.string.th_permission_compat_calendar);
                break;
            case Manifest.permission_group.CAMERA:
                explanation = context.getString(R.string.th_permission_compat_camera);
                break;
            case Manifest.permission_group.CALL_LOG:
                explanation = context.getString(R.string.th_permission_compat_call_log);
                break;
            case Manifest.permission_group.PHONE:
                explanation = context.getString(R.string.th_permission_compat_phone);
                break;
            case Manifest.permission_group.CONTACTS:
                explanation = context.getString(R.string.th_permission_compat_contacts);
                break;
            case Manifest.permission_group.LOCATION:
                explanation = context.getString(R.string.th_permission_compat_location);
                break;
            case Manifest.permission_group.SENSORS:
                explanation = context.getString(R.string.th_permission_compat_sensors);
                break;
            case Manifest.permission_group.SMS:
                explanation = context.getString(R.string.th_permission_compat_sms);
                break;
            case Manifest.permission_group.ACTIVITY_RECOGNITION:
                explanation = context.getString(R.string.th_permission_compat_activity_recognition);
                break;
            case Manifest.permission_group.NEARBY_DEVICES:
                explanation = context.getString(R.string.th_permission_compat_nearby_devices);
                break;
            default:
                explanation = null;
        }
        return explanation;
    }
}
